"""
崩溃堆栈解析模块
"""
import re
import subprocess
import pandas as pd
import os
from typing import List, Dict, Union, Optional, Tuple


class CrashStackParser:
    """iOS崩溃堆栈解析器"""
    
    def __init__(self, dsym_path: str):
        """
        初始化解析器
        
        Args:
            dsym_path: dSYM文件或目录路径
        """
        self.dsym_path = dsym_path
        self._validate_dsym()
    
    def _validate_dsym(self) -> bool:
        """验证dSYM文件是否存在且有效"""
        if not os.path.exists(self.dsym_path):
            raise FileNotFoundError(f"dSYM路径不存在: {self.dsym_path}")
        
        # TODO: 实现更详细的dSYM文件验证逻辑
        return True
    
    def parse_stack(self, crash_line: str) -> str:
        """
        解析单行崩溃堆栈
        
        Args:
            crash_line: 崩溃堆栈行
            
        Returns:
            解析后的可读堆栈信息
        """
        # 提取地址和二进制文件信息的正则表达式
        # 示例格式: 0x0000000102a24000 MyApp + 2293760
        pattern = r"(0x[0-9a-f]+)\s+(\S+)\s+\+\s+(\d+)"
        match = re.search(pattern, crash_line)
        
        if not match:
            return f"无法解析: {crash_line}"
        
        address = match.group(1)
        binary_name = match.group(2)
        offset = match.group(3)
        
        # 调用atos工具进行符号化
        try:
            result = self._run_atos(binary_name, address)
            return result if result else f"未解析: {crash_line}"
        except Exception as e:
            return f"解析错误 ({str(e)}): {crash_line}"
    
    def _run_atos(self, binary_name: str, address: str) -> str:
        """
        运行atos命令解析地址
        
        Args:
            binary_name: 二进制文件名
            address: 内存地址
            
        Returns:
            解析后的符号信息
        """
        # 构建atos命令
        # atos -o [dSYM文件路径] -arch arm64 -l [加载地址] [需要解析的地址]
        cmd = [
            "atos",
            "-o", self.dsym_path,
            "-arch", "arm64",  # 假设是arm64架构
            address
        ]
        
        # 执行命令
        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                check=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError as e:
            raise RuntimeError(f"atos命令执行失败: {e.stderr}")
    
    def parse_file(self, input_file: str, progress_callback=None) -> pd.DataFrame:
        """
        解析整个崩溃文件
        
        Args:
            input_file: 输入文件路径（CSV或TXT）
            progress_callback: 进度回调函数
            
        Returns:
            包含解析结果的DataFrame
        """
        # 根据文件扩展名决定处理方式
        ext = os.path.splitext(input_file)[1].lower()
        
        if ext == '.csv':
            return self._parse_csv(input_file, progress_callback)
        elif ext == '.txt':
            return self._parse_txt(input_file, progress_callback)
        else:
            raise ValueError(f"不支持的文件格式: {ext}")
    
    def _parse_csv(self, csv_file: str, progress_callback=None) -> pd.DataFrame:
        """解析CSV文件"""
        # 读取CSV文件
        df = pd.read_csv(csv_file)
        
        # 查找包含崩溃堆栈的列
        stack_cols = self._find_stack_columns(df)
        if not stack_cols:
            raise ValueError("未找到包含崩溃堆栈的列")
        
        # 添加解析后的列
        for col in stack_cols:
            result_col = f"{col}_parsed"
            df[result_col] = ""
            
            # 处理每一行
            total_rows = len(df)
            for idx, row in df.iterrows():
                stack = row[col]
                if isinstance(stack, str):
                    df.at[idx, result_col] = self.parse_stack(stack)
                
                # 更新进度
                if progress_callback and idx % 10 == 0:
                    progress_callback(idx / total_rows * 100)
        
        return df
    
    def _parse_txt(self, txt_file: str, progress_callback=None) -> pd.DataFrame:
        """解析TXT文件"""
        # 读取文本文件
        with open(txt_file, 'r') as f:
            lines = f.readlines()
        
        # 创建DataFrame
        results = []
        total_lines = len(lines)
        
        for idx, line in enumerate(lines):
            line = line.strip()
            if line:  # 忽略空行
                parsed = self.parse_stack(line)
                results.append({
                    'original': line,
                    'parsed': parsed
                })
            
            # 更新进度
            if progress_callback and idx % 10 == 0:
                progress_callback(idx / total_lines * 100)
        
        return pd.DataFrame(results)
    
    def _find_stack_columns(self, df: pd.DataFrame) -> List[str]:
        """
        查找包含崩溃堆栈的列
        
        Args:
            df: 输入DataFrame
            
        Returns:
            可能包含崩溃堆栈的列名列表
        """
        stack_cols = []
        
        # 检查每一列
        for col in df.columns:
            # 取样检查是否包含常见的崩溃堆栈模式
            sample = df[col].dropna().head(10).astype(str)
            
            # 检查是否包含地址模式 (0x...)
            if any(sample.str.contains('0x[0-9a-f]+', regex=True)):
                stack_cols.append(col)
        
        return stack_cols 